package com.example.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.entity.dto.MathTool.MathTool;
import com.example.entity.vo.request.math.*;
import com.example.entity.vo.response.math.*;
import com.example.mapper.MathToolMapper;
import com.example.service.MathToolService;
import com.example.utils.MathUtil;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static com.example.utils.MathUtil.*;

/**
 * 数学工具服务接口实现类
 *
 * @auth shanyue
 * @date 2025年07月09日14:31
 */
@Service
public class MathToolServiceImpl extends ServiceImpl<MathToolMapper, MathTool> implements MathToolService {

    /**
     * 根据路径参数查询对应的数学工具详细信息
     *
     * @param path 工具的唯一路径标识
     * @return 返回对应的MathTool对象，不存在返回null
     */
    @Override
    public MathTool getInfoByPath(String path) {
        return lambdaQuery()
                .eq(MathTool::getPath, path)
                .one();
    }

    /**
     * 根据请求参数执行数字与中文金额的转换
     *
     * @param requestVO 请求对象，包含转换类型和文本内容
     * @return 转换结果封装的响应对象，转换异常时返回错误信息
     */
    @Override
    public NumberChangeResponseVO getNumberChangeResult(NumberChangeRequestVO requestVO) {
        String type = requestVO.getType();
        String text = requestVO.getText();
        String result;
        try {
            if ("numberToChinese".equalsIgnoreCase(type)) {
                BigDecimal number = new BigDecimal(text);
                result = numberToChinese(number);
            } else if ("chineseToNumber".equalsIgnoreCase(type)) {
                result = chineseToNumber(text)
                        .stripTrailingZeros()
                        .toPlainString();
            } else {
                result = "类型错误";
            }
        } catch (Exception e) {
            result = "转换错误: " + e.getMessage();
        }
        return new NumberChangeResponseVO(result);
    }

    /**
     * 根据请求的面积类型和数据，返回所有面积单位的换算结果
     *
     * @param requestVO 请求体，包含面积单位类型和数值字符串
     * @return 封装了各面积换算值的响应对象
     */
    @Override
    public AreaChangeResponseVO getAreaChangeResult(AreaChangeRequestVO requestVO) {
        //获取面积类型
        String type = requestVO.getType();
        //获取数值
        String text = requestVO.getText();

        // 解析输入数值，精确计算
        BigDecimal inputValue;
        try {
            inputValue = new BigDecimal(text);
        } catch (Exception e) {
            throw new IllegalArgumentException("输入数值格式不正确");
        }

        // 先把输入单位换算成平方米
        BigDecimal valueInM2 = MathUtil.toSquareMeter(type, inputValue);

        // 再从平方米换算成所有单位
        AreaChangeResponseVO response = new AreaChangeResponseVO();
        response.setMm2(MathUtil.fromSquareMeter("mm2", valueInM2).stripTrailingZeros().toPlainString());
        response.setCm2(MathUtil.fromSquareMeter("cm2", valueInM2).stripTrailingZeros().toPlainString());
        response.setDm2(MathUtil.fromSquareMeter("dm2", valueInM2).stripTrailingZeros().toPlainString());
        response.setM2(valueInM2.stripTrailingZeros().toPlainString());
        response.setKm2(MathUtil.fromSquareMeter("km2", valueInM2).stripTrailingZeros().toPlainString());
        response.setMu(MathUtil.fromSquareMeter("mu", valueInM2).stripTrailingZeros().toPlainString());
        response.setHa(MathUtil.fromSquareMeter("ha", valueInM2).stripTrailingZeros().toPlainString());
        response.setFt2(MathUtil.fromSquareMeter("ft2", valueInM2).stripTrailingZeros().toPlainString());
        response.setMi2(MathUtil.fromSquareMeter("mi2", valueInM2).stripTrailingZeros().toPlainString());
        response.setIn2(MathUtil.fromSquareMeter("in2", valueInM2).stripTrailingZeros().toPlainString());
        response.setAc(MathUtil.fromSquareMeter("ac", valueInM2).stripTrailingZeros().toPlainString());

        return response;
    }

    /**
     * 根据请求体中的单位类型和数值，执行字节单位换算功能
     *
     * @param requestVO 请求体，包含字节单位类型(type)和输入数值(text)
     * @return 返回所有字节单位换算后的结果列表，List中每个对象包含单位标签和转换后的数值字符串
     */
    @Override
    public List<ByteChangeResponseVO> getByteChangeResult(ByteChangeRequestVO requestVO) {
        String fromUnit = requestVO.getType();
        String text = requestVO.getText();

        // 校验
        if (!BYTE_UNIT_TO_BYTE.containsKey(fromUnit)) {
            throw new IllegalArgumentException("不支持的单位：" + fromUnit);
        }

        BigDecimal inputValue;
        try {
            inputValue = new BigDecimal(text);
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("输入数值无效：" + text);
        }

        // 统一转换为“字节(B)”
        BigDecimal valueInBytes = inputValue.multiply(BYTE_UNIT_TO_BYTE.get(fromUnit));

        // 计算所有单位的换算值
        List<ByteChangeResponseVO> resultList = new ArrayList<>();
        for (Map.Entry<String, BigDecimal> entry : BYTE_UNIT_TO_BYTE.entrySet()) {
            String targetUnit = entry.getKey();
            BigDecimal unitFactor = entry.getValue();

            BigDecimal converted = valueInBytes.divide(unitFactor, 10, RoundingMode.HALF_UP);
            String label = BYTE_UNIT_LABELS.get(targetUnit);

            resultList.add(new ByteChangeResponseVO(label, converted.stripTrailingZeros().toPlainString()));
        }

        return resultList;
    }

    /**
     * 执行长度单位的换算，并按照指定顺序返回各个单位对应的数值
     *
     * @param requestVO 请求体，包含类型(type)和数值(text)
     * @return 长度单位换算结果列表，列表中每项包含单位的中文标签和换算后的结果，保留10位小数并去除多余的0
     */
    @Override
    public List<LengthChangeResponseVO> getLengthChangeResult(LengthChangeRequestVO requestVO) {
        String fromUnit = requestVO.getType();
        String text = requestVO.getText();

        if (!LENGTH_UNIT_TO_METER.containsKey(fromUnit)) {
            throw new IllegalArgumentException("不支持的单位：" + fromUnit);
        }

        BigDecimal inputValue;
        try {
            inputValue = new BigDecimal(text);
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("输入数值无效：" + text);
        }

        BigDecimal valueInMeters = inputValue.multiply(LENGTH_UNIT_TO_METER.get(fromUnit));

        // 自定义顺序列表
        List<String> orderedUnits = List.of("mm", "cm", "dm", "m", "in", "ft", "mi");

        List<LengthChangeResponseVO> result = new ArrayList<>();

        for (String unit : orderedUnits) {
            BigDecimal factor = LENGTH_UNIT_TO_METER.get(unit);
            BigDecimal convertedValue = valueInMeters.divide(factor, 10, RoundingMode.HALF_UP).stripTrailingZeros();
            result.add(new LengthChangeResponseVO(LENGTH_UNIT_LABELS.get(unit), convertedValue.toPlainString()));
        }

        return result;
    }

    /**
     * 执行质量单位换算，将用户输入的某一单位的质量数值转换为多个常量单位对应的数值
     *
     * @param requestVO 请求体，包含单位类型和数值
     * @return 质量换算结果列表，每项为不同单位下的转换数值
     */
    @Override
    public List<QualityChangeResponseVO> getQualityChangeResult(QualityChangeRequestVO requestVO) {
        // 获取用户输入的单位和数值
        String fromUnit = requestVO.getType();
        String textValue = requestVO.getValue();

        // 校验单位是否受支持
        if (!QUALITY_UNIT_TO_KG.containsKey(fromUnit)) {
            throw new IllegalArgumentException("不支持的单位: " + fromUnit);
        }

        // 尝试将输入数值转换为 BigDecimal
        BigDecimal inputValue;
        try {
            inputValue = new BigDecimal(textValue);
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("输入数值无效: " + textValue);
        }

        // 将输入值统一转换为千克（kg）作为中间换算单位
        BigDecimal valueInKg = inputValue.multiply(QUALITY_UNIT_TO_KG.get(fromUnit));

        // 规定输出顺序：从最小单位到最大单位
        List<String> orderedUnits = List.of("mcg", "mg", "g", "kg", "jin", "oz", "lb", "mt", "t");

        List<QualityChangeResponseVO> result = new ArrayList<>();

        // 遍历所有单位，按顺序换算并封装结果
        for (String unit : orderedUnits) {
            BigDecimal factor = QUALITY_UNIT_TO_KG.get(unit);
            if (factor == null || factor.compareTo(BigDecimal.ZERO) == 0) continue;

            BigDecimal convertedValue = valueInKg.divide(factor, 10, RoundingMode.HALF_UP)
                    .stripTrailingZeros();

            result.add(new QualityChangeResponseVO(
                    QUALITY_UNIT_LABELS.getOrDefault(unit, unit), // 防止 null
                    convertedValue.toPlainString()
            ));
        }
        return result;
    }

    /**
     * 根据输入的时间单位和数值，换算成其他时间单位的对应数值列表
     *
     * @param requestVO 请求体，包含输入时间单位(type)和输入时间字符串(text)
     * @return 按顺序封装的时间单位换算结果列表，每项包含单位标签和对应换算值字符串
     */
    @Override
    public List<TimeChangeResponseVO> getTimeChangeResult(TimeChangeRequestVO requestVO) {
        String fromUnit = requestVO.getType();
        String textValue = requestVO.getText();
        if (!TIME_UNIT_TO_SECOND.containsKey(fromUnit)) {
            throw new IllegalArgumentException("不支持的单位: " + fromUnit);
        }

        BigDecimal inputValue;
        try {
            inputValue = new BigDecimal(textValue);
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("输入数值无效: " + textValue);
        }

        // 转换为秒
        BigDecimal valueInSeconds = inputValue.multiply(TIME_UNIT_TO_SECOND.get(fromUnit));

        // 返回顺序保持和单位数组一致
        List<String> orderedUnits = List.of("ns", "μs", "ms", "s", "min", "h", "d", "week", "month", "year");

        List<TimeChangeResponseVO> result = new ArrayList<>();
        for (String unit : orderedUnits) {
            BigDecimal factor = TIME_UNIT_TO_SECOND.get(unit);
            if (factor == null || factor.compareTo(BigDecimal.ZERO) == 0) continue;

            BigDecimal convertedValue = valueInSeconds.divide(factor, 10, RoundingMode.HALF_UP).stripTrailingZeros();

            result.add(new TimeChangeResponseVO(
                    TIME_UNIT_LABELS.getOrDefault(unit, unit),
                    convertedValue.toPlainString()
            ));
        }
        return result;
    }

    /**
     * 数字转中文金额
     *
     * @param number 待转换的数字
     * @return 转换后的中文金额字符串
     */
    private String numberToChinese(BigDecimal number) {
        if (number.compareTo(BigDecimal.ZERO) == 0) {
            return "零元整";
        }

        StringBuilder sb = new StringBuilder();
        long integerPart = number.longValue();
        int sectionUnitPos = 0;

        //处理整数部分，按四位分节转换
        while (integerPart > 0) {
            int section = (int) (integerPart % 10000);
            if (section != 0) {
                StringBuilder sectionStr = new StringBuilder();
                boolean zeroFlag = false;

                for (int i = 0; i < 4; i++) {
                    int digit = section % 10;
                    if (digit != 0) {
                        sectionStr.insert(0, CN_NUM[digit] + CN_UNIT[i]);
                        zeroFlag = false;
                    } else if (!zeroFlag) {
                        sectionStr.insert(0, CN_NUM[0]);
                        zeroFlag = true;
                    }
                    section /= 10;
                }

                String sectionResult = sectionStr.toString()
                        .replaceAll("零+", "零")//连续多个零合并为一个零
                        .replaceAll("零$", "");//去除结尾零
                sb.insert(0, sectionResult + CN_SECTION_UNIT[sectionUnitPos]);
            } else if (!sb.toString().startsWith("零")) {
                sb.insert(0, "零");
            }

            integerPart /= 10000;
            sectionUnitPos++;
        }

        sb.append("元");

        // 处理小数部分(角、分)
        BigDecimal fraction = number.remainder(BigDecimal.ONE);
        int jiao = fraction.multiply(BigDecimal.TEN).intValue();
        int fen = fraction.multiply(new BigDecimal("100")).intValue() % 10;

        if (jiao == 0 && fen == 0) {
            sb.append("整");
        } else {
            if (jiao > 0) sb.append(CN_NUM[jiao]).append("角");
            if (fen > 0) sb.append(CN_NUM[fen]).append("分");
        }

        return sb.toString()
                .replaceAll("零+", "零")//多余零合并
                .replaceAll("零元", "元")//去除零元
                .replaceAll("零角", "")//去除零角
                .replaceAll("零分", "");//去除零分
    }


    /**
     * 中文金额转数字
     *
     * @param chinese 中文金额字符串
     * @return 转换后的数字
     */
    private BigDecimal chineseToNumber(String chinese) {
        chinese = chinese.replace("元", "").replace("整", "");

        BigDecimal result = BigDecimal.ZERO;

        String[] sections = {"兆", "亿", "万", ""};
        long[] sectionValues = {1_000_000_000_000L, 100_000_000L, 10_000L, 1L};

        //按大单位拆分处理
        for (int i = 0; i < sections.length; i++) {
            if (chinese.contains(sections[i]) && !sections[i].isEmpty()) {
                String part = chinese.substring(0, chinese.indexOf(sections[i]));
                chinese = chinese.substring(chinese.indexOf(sections[i]) + 1);
                result = result.add(parseSection(part).multiply(BigDecimal.valueOf(sectionValues[i])));
            }
        }

        //处理余下部分
        if (!chinese.isEmpty() && !chinese.contains("角") && !chinese.contains("分")) {
            result = result.add(parseSection(chinese));
            chinese = "";
        }

        //处理小数部分，角
        if (chinese.contains("角")) {
            int index = chinese.indexOf("角");
            char c = chinese.charAt(index - 1);
            if (CN_TO_NUM.containsKey(c)) {
                result = result.add(BigDecimal.valueOf(CN_TO_NUM.get(c)).multiply(BigDecimal.valueOf(0.1)));
            }
        }

        //处理小数部分，分
        if (chinese.contains("分")) {
            int index = chinese.indexOf("分");
            char c = chinese.charAt(index - 1);
            if (CN_TO_NUM.containsKey(c)) {
                result = result.add(BigDecimal.valueOf(CN_TO_NUM.get(c)).multiply(BigDecimal.valueOf(0.01)));
            }
        }

        // 处理无单位数字情况，如“伍拾伍”
        if (result.compareTo(BigDecimal.ZERO) == 0 && !chinese.isEmpty()) {
            result = parseSection(chinese);
        }

        return result;
    }

    /**
     * 解析一个“仟佰拾”小节中的中文数字部分
     *
     * @param part 小节字符串，如壹仟贰佰叁拾肆
     * @return 转换成对应数字的BigDecimal值
     */
    private BigDecimal parseSection(String part) {
        BigDecimal sectionValue = BigDecimal.ZERO;
        BigDecimal digit = BigDecimal.ZERO;

        for (int i = 0; i < part.length(); i++) {
            char c = part.charAt(i);
            if (CN_TO_NUM.containsKey(c)) {
                //当前字符为数字，记录数值
                digit = BigDecimal.valueOf(CN_TO_NUM.get(c));
            } else {
                //当前字符为单位，乘以对应单位
                BigDecimal unit = switch (c) {
                    case '拾' -> BigDecimal.TEN;
                    case '佰' -> BigDecimal.valueOf(100);
                    case '仟' -> BigDecimal.valueOf(1000);
                    default -> BigDecimal.ONE;
                };
                //末尾可能时纯数字无单位，直接加上
                sectionValue = sectionValue.add(digit.multiply(unit));
                digit = BigDecimal.ZERO;
            }
        }
        // 末尾如果最后是数字没有单位，直接加上
        sectionValue = sectionValue.add(digit);

        return sectionValue;
    }

}
